﻿using System;
using System.Collections.Generic;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;


namespace CCPSIP.Message
{
    /// <summary>CCPSIP_015：下載訊息檔案 API</summary>
    ///idHeader = 裝置 UUID 前八碼。iOS 請使用 [CCPCrypto getIdHeader] 呼叫。
    /// checkcode = 裝置限時驗證碼。iOS 請使用 [CCPCrypto getCheckcode] 呼叫。
    /// ChatID = 聊天ID(對方帳號或ClientGID)。
    /// MsgType = 訊息類型，目前支援 ("P", "V", "I")。
    /// filename = 檔案名稱。

    public class file_get : IHttpHandler
    {
        private string kFilesRootDir = ChrisKit.RootDir + "CCPSIP\\Files";//ios.ccp.com.tw
        private static Dictionary<string, string> kMsgTypeDirs = new Dictionary<string, string>() {
      { "P", "Photo" }, { "V", "Video" }, { "I", "Sticker" }, { "D", "Document" }, {"A", "Audio"}
    };
        private const string kHashStickerDir = "StickerHash";
        private const string kHashNamePattern = @"^[2-9][0-9]{3}_[0-9]+_[0-9a-f]{32,}";//YYYY_Size_Hash
        private static Dictionary<string, string> kDocumentContentTypeDict = new Dictionary<string, string>() {
      { ".pdf", "application/pdf" },
      { ".doc", "application/msword" }, { ".docx", "application/msword" },
      { ".ppt", "application/vnd.ms-powerpoint" }, { ".pptx", "application/vnd.ms-powerpoint" },
      { ".xls", "application/vnd.ms-excel" }, { ".xlsx", "application/vnd.ms-excel" },
      { ".txt", "text/plain" }, { ".rtf", "application/rtf" },
      { ".epub", "application/epub+zip" },
      { ".html", "text/html" }, { ".htm", "text/html" },
      { ".pages", "application/x-iwork-pages-sffpages" },
      { ".key", "application/x-iwork-keynote-sffkey" },
      { ".numbers", "application/x-iwork-numbers-sffnumbers" },
    };
        //private static Dictionary<string, string> kAudioContentTypeDict = new Dictionary<string, string>()
        //{
        //     {".m4a", "audio/m4a"},
        //     {".mp4", "video/mp4"},
        //     {".mp3", "audio/mpeg"},
        //};

        public void ProcessRequest(HttpContext context)
        {
            HttpRequest req = context.Request;
            HttpResponse resp = context.Response;
            resp.ContentType = "text/plain";
            resp.ContentEncoding = System.Text.Encoding.UTF8;
            DateTime reqTime = DateTime.Now;

            try
            {
                //【01】取得POST參數，驗證身分
                //
                string idHeader = req.Form["idHeader"];
                string checkcode = req.Form["checkcode"];
                string ChatID = req.Form["ChatID"];//聊天ID(對方帳號或ClientGID)
                string MsgType = req.Form["MsgType"];//訊息類型
                string filename = req.Form["filename"];//檔案名稱

                SipUserInfo userInfo = SipKit.GetUserInfo(idHeader, checkcode, req);
                if (userInfo == null)
                {
                    throw new Exception("Error_01: Cannot identify this device");//無法識別此裝置
                }

                if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
                {
                    throw new Exception("Error_02: Filename Error");//檔名錯誤
                }


                //【02】設定MIME類別
                //
                if (MsgType == "P")
                    resp.ContentType = "image/jpeg";
                else if (MsgType == "V")
                {
                    if (filename.ToLower().EndsWith(".jpg"))
                        resp.ContentType = "image/jpeg";
                    else
                        resp.ContentType = "video/quicktime";   //Andorid裝置也會收到.mov的影片檔
                }
                else if (MsgType == "I")
                    resp.ContentType = "image/png";
                else if (MsgType == "D")
                {
                    string fileExt = Path.GetExtension(filename).ToLower();
                    bool isExtSupport = false;
                    foreach (string typeKey in kDocumentContentTypeDict.Keys)
                    {
                        if (fileExt == typeKey)
                        {
                            isExtSupport = true;
                            resp.ContentType = kDocumentContentTypeDict[typeKey];
                            break;
                        }
                    }
                    if (!isExtSupport)
                        throw new Exception("Error_03: Document type not support");//不支援的文件類型
                }
                else if (MsgType == "A")
                    resp.ContentType = "audio/m4a";     //Andorid裝置也會收到.m4a的影片檔
                else
                {
                    throw new Exception("Error_05: Message type not support");//不支援的訊息類型
                }


                //【03】檢查檔案存取權限
                //
                bool isHashSticker = (MsgType == "I" && Regex.IsMatch(filename, kHashNamePattern));
                string FileDate = null;//yyyyMMdd

                if (!isHashSticker)
                {
                    UInt32 MsgID = 0;
                    bool isGroup = SipKit.isGroupID(ChatID);

                    try
                    {
                        char[] separators = { '_', '.' };
                        string[] fileKeyArray = filename.Split(separators, StringSplitOptions.None);
                        if (isGroup)
                        {
                            MsgID = Convert.ToUInt32(fileKeyArray[2]);
                            FileDate = fileKeyArray[1].Trim();
                        }
                        else
                        {
                            MsgID = Convert.ToUInt32(fileKeyArray[1]);
                            FileDate = fileKeyArray[0].Trim();
                        }
                    }
                    catch (Exception ex)
                    {
                        ChrisKit.SkipVar(ex);
                        throw new Exception("Error_06: Filename Error");//檔名錯誤
                    }

                    if (isGroup)
                    {
                        if (!OracleKitMsg.canAccessGroupFile(userInfo, MsgID, filename))
                            throw new Exception("Error_07: You have no right to access this file");//無權限存取此檔案
                    }
                    else
                    {
                        if (!OracleKitMsg.canAccessFile(userInfo, MsgID, filename))
                            throw new Exception("Error_07: You have no right to access this file");//無權限存取此檔案
                    }
                }


                //【98】組合檔名路徑，檢查檔案是否存在
                //
                string targetDir = kFilesRootDir;

                if (isHashSticker)
                {
                    //【98-1】Hash貼圖的資料夾規則不同
                    //
                    string FileYear = filename.Substring(0, 4);
                    targetDir = string.Format(@"{0}\{1}\{2}", kFilesRootDir, kHashStickerDir, FileYear);
                }
                else
                {
                    targetDir = string.Format(@"{0}\{1}\{2}\{3}",
                      kFilesRootDir, kMsgTypeDirs[MsgType], FileDate.Substring(0, 4), FileDate.Substring(4, 2));
                }
                string targetPath = string.Format(@"{0}\{1}", targetDir, filename);

                if (!File.Exists(targetPath))
                {
                    throw new Exception("Error_08: File not found");//檔案不存在
                }


                //【99】回傳檔案內容
                //
                FileInfo fInfo = new FileInfo(targetPath);
                resp.AppendHeader("Content-Length", fInfo.Length.ToString());
                resp.AppendHeader("Last-Modified", fInfo.LastWriteTime.ToUniversalTime().ToString("r"));
                resp.AppendHeader("Content-Disposition", ChrisKit.getContentDisposition(filename));
                if (fInfo.Length >= 4 * 1048576)
                    resp.TransmitFile(targetPath);//Large File
                else
                    resp.WriteFile(targetPath, true);//Small File
            }
            catch (Exception ex)
            {
                resp.ContentType = "application/xml";
                string resultStr = ChrisKit.Ex2Xml(ex, false);
                int contentLength = resp.ContentEncoding.GetByteCount(resultStr);
                resp.AppendHeader("Content-Length", contentLength.ToString());
                resp.Write(resultStr);
            }
            finally
            {
                resp.Flush();
                resp.Close();
            }
        }


        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

    }
}
